""" This is the meat of the web-server. """

import cherrypy as web,time,hashlib
from libs import dbcontrol
class WebServer: # this is the class which contains the server's code
  header = ''
  body = ''
  footer = ''
  title = ''
  prompt = ''
  battlebody = ''
  
  db = [] # database of images
  
  battles = {} # list of battles currently in play
  
  def setHTML(self):
    # This function loads the header, footer, and body from files in the "include" directory
    self.header = open('include/header.htm').read()
    self.body = open('include/body.htm').read()
    self.footer = open('include/footer.htm').read()
    self.battlebody = open('include/battle.htm').read()
  
  def output(self,body,script='function displayunicode(e){}'):
    # This function builds the page we want to return
    output = self.header + self.body + self.footer # all pages start this way
    output = output.replace("$TITLE",self.title)
    output = output.replace("$BODY",body)
    output = output.replace("$SCRIPT",script)
    return output
  
  def getBattleID(self,images):
    # register a battle for this pair of images
    ID = images[0] + images[1] # make a string that's a concatenation of both filenames
    timestamp = time.time()
    ID += "%d" % (timestamp) # append a timestamp
    m = hashlib.md5() # initialize a hash library
    m.update(ID) # set the value inside
    ID = "%s" % (m.hexdigest()) # set the ID as a MD5sum of the ID
    self.battles[ID] = (images,timestamp) # append the battle to the list
    return ID
  
  def vote(self,battle,vote):
    # register a winner
    try:
      (images,timestamp) = self.battles[battle]
      winner = ""
      loser = ""
      if vote == "1":
        winner = images[0] # the first image won
        loser = images[1]
      else:
        winner = images[1] # the second image won
        loser = images[0]
      self.db.vote(winner,loser)
      del self.battles[battle]
    except:
      # that battle doesn't exist
      pass
  
  def pruneBattles(self):
    # prune any keys older than 60 seconds.
    now = time.time()
    dropped = 0
    for key in self.battles.keys():
      (images,timestamp) = self.battles[key]
      if((now - timestamp) > 60):
        del self.battles[key]
        dropped = dropped + 1
  
  # The following functions define the various sections of the website
  def index(self,vote=None,battle=None,skip=None,drop=None): # the index page
    body = self.battlebody.replace("$PROMPT",self.prompt)
    if skip != None:
      # someone wanted to skip a battle, remove it from memory
      del self.battles[skip] # delete it
    if vote != None and battle != None:
      # Someone voted for a picture!
      self.vote(battle,vote) # register that vote
    if drop != None:
      (images,timestamp) = self.battles[battle]
      if(drop == "1"):
        self.vote(battle,"2")
        self.db.drop(images[0])
      elif(drop == "2"):
        self.vote(battle,"1")
        self.db.drop(images[1])
      elif(drop == "3"):
        self.db.drop(images[0])
        self.db.drop(images[1])
    images = self.db.pick() # get new images to battle
    body = body.replace("$FIRST",images[0]) # set the URL for the first one
    body = body.replace("$SECOND",images[1]) # set the URL for the second one
    battle = self.getBattleID(images) # get the battle ID
    body = body.replace("$BATTLE",battle) # set the battle ID in source
    body = body.replace("$SKIP","/?skip=%s" % battle) # allow them to skip a battle and remove it from memory
    self.pruneBattles()
    script = """
      function displayunicode(e){
        var unicode=e.keyCode? e.keyCode : e.charCode
        if(unicode == 49){
            // key: 1
            window.location = "$FIRST";
	}else if(unicode == 50){
            // key: 2
	    window.location = "$SECOND";
	}else if(unicode == 115){
            // key: s
            window.location = "$DROPLEFT";
        }else if(unicode == 100){
            // key: d
            window.location = "$DROPBOTH";
        }else if(unicode == 102){
            // key: f
            window.location = "$DROPRIGHT";
        }
      }
    """
    script = script.replace("$FIRST","?battle=%s&vote=1" % (battle))
    script = script.replace("$SECOND","?battle=%s&vote=2" % (battle))
    script = script.replace("$DROPLEFT","?battle=%s&drop=1" % (battle))
    script = script.replace("$DROPRIGHT","?battle=%s&drop=2" % (battle))
    script = script.replace("$DROPBOTH","?battle=%s&drop=3" % (battle))
    return self.output(body,script)
  index.exposed = True # this page is visible
  
  def view(self,start=0):
    # This is for viewing the images in order of rating
    try:
      howmany = self.db.howmany
    except:
      howmany = 20
    start = int(start)
    back = "<a href='view?start=%d'>PREV</a>" % (start-howmany)
    forward = "<a href='view?start=%d'>NEXT</a>" % (start+howmany)
    nav = forward
    toplist = self.db.toplist(howmany,start)
    if (start-howmany) >= 0:
      if len(toplist) == howmany:
        nav = back
        temp = self.db.toplist(howmany,start+howmany)
        if(len(temp) > 0):
          nav = nav + " | " + forward
      else:
        nav = back
    nav += "<br><br>"
    body = ""
    for image in toplist:
      url = image[0]
      wins = image[1]
      losses = image[2]
      rating = image[3]
      body += "<a href='%s'><img style='border:6px solid black;width:600px;height:auto' src='%s'></a><br>Wins: %d | Losses: %d | Rating: %d <br><br>" % (url,url,wins,losses,rating)
    body = nav + body + nav
    return self.output(body)
  view.exposed = True # show this page
  
  def purge(self,do='no'):
    # this is to purge all images that are rated less than 20%
    if do == "yes":
      # purge
      self.db.purge()
      body = "All files with a rating of 20% or lower have been deleted (with the exception of files with fewer than 5 wins or losses)."
    else:
      body = "This will delete all files with a 20% or lower rating.<br>Do you wish to continue?<br><a href='purge?do=yes'>YES</a> | <a href='/'>NO</a>"
    return self.output(body)
  purge.exposed = True # show this page
  
  def retire(self,do='no'):
    # this is to retire all images that are rated less than 20%
    if do == "yes":
      # retire
      self.db.retire()
      body = "All files with a rating of 80% or higher have been retired (with the exception of files with fewer than 5 wins or losses)."
    else:
      body = "This will retire all files with an 80% or higher rating.<br>Do you wish to continue?<br><a href='retire?do=yes'>YES</a> | <a href='/'>NO</a>"
    return self.output(body)
  retire.exposed = True # show this page
  
  def settings(self,autoprune='false',resevoir='true',forcerotate='false',poolsize='60',howmany='20',update='false'):
    # This is where we set the server's settings.
    body = "<h3>Server Settings</h3>"
    if(update=='true'): # They're changing settings
      self.db.setsettings(autoprune,resevoir,forcerotate,poolsize,howmany)
      body += "<h4>Settings updated.</h4>"
    # Pull the settings from the database to ensure they're set properly.
    (autoprune,resevoir,forcerotate,poolsize,howmany) = self.db.getsettings()
    # Let's set up some variables.
    settings={
      "$pruneoff":"",
      "$pruneon":"",
      "$resevoiroff":"",
      "$resevoiron":"",
      "$rotateon":"",
      "$rotateoff":""
    }
    # Tell the system which settings to select based on what's currently enabled
    if(autoprune == u'true'):
      settings["$pruneon"] = "checked"
    else:
      settings["$pruneoff"] = "checked"
    if(resevoir == u'true'):
      settings["$resevoiron"] = "checked"
    else:
      settings["$resevoiroff"] = "checked"
    if(forcerotate == u'true'):
      settings["$rotateon"] = "checked"
    else:
      settings["$rotateoff"] = "checked"
    # Now we display the form
    body += """
      <form name="settings" action="settings" method="post">
        <input type="hidden" name="update" value="true">
        <table style="width:150px;margin-left:auto;margin-right:auto;" border="0">
          <tr>
            <th align="left">Setting</th>
            <th>Off</th>
            <th align="right">On</th>
          </tr>
          <tr>
            <td>Auto-Prune</td>
            <td align="right">
              <input type="radio" name="autoprune" value="false" $pruneoff>
            </td>
            <td align="right">
              <input type="radio" name="autoprune" value="true" $pruneon>
            </td>
          </tr>
          <tr>
            <td>Use Resevoir</td>
            <td align="right">
              <input type="radio" name="resevoir" value="false" $resevoiroff>
            </td>
            <td align="right">
              <input type="radio" name="resevoir" value="true" $resevoiron>
            </td>
          </tr>
          <tr>
            <td>Force Rotate</td>
            <td align="right">
              <input type="radio" name="forcerotate" value="false" $rotateoff>
            </td>
            <td align="right">
              <input type="radio" name="forcerotate" value="true" $rotateon>
            </td>
          </tr>
          <tr>
            <td colspan = "2">Pool Size</td>
            <td align="right">
              <input type="text" name="poolsize" size="3" value="$POOLSIZE">
            </td>
          </tr>
          <tr>
            <td colspan = "2">Results Per Page</td>
            <td align="right">
              <input type="text" name="howmany" size="3" value="$HOWMANY">
            </td>
          </tr>
        </table>
        <input type="submit" value="Submit">
      </form>
    """
    # Set which ones are checked
    for key in settings.keys():
      body = body.replace(key,settings[key])
    body = body.replace("$POOLSIZE",poolsize)
    body = body.replace("$HOWMANY",howmany)
    return self.output(body)
  settings.exposed = True # show this page
  
  def __init__(self,title,prompt):
    self.title = title
    self.prompt = prompt
    self.db = dbcontrol.db()
    self.setHTML()
    self.battles = {}
